home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Linux Cubed Series 8: LINUX Games
/
Linux Cubed Series 8 - LINUX Games.iso
/
games
/
muds
/
mordor_2.000
/
mordor_2
/
src
/
io.c
< prev
next >
Wrap
C/C++ Source or Header
|
1995-06-21
|
26KB
|
1,055 lines
/*
* IO.C:
*
* Socket input/output/establishment functions.
*
* Copyright (C) 1991, 1992, 1993 Brett J. Vickers
*
*/
#include <stdio.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/signal.h>
#include <sys/wait.h>
#include <sys/time.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <errno.h>
#include <string.h>
#include "mstruct.h"
#include "mextern.h"
#define buflen(a,b,c) (a-b + (a<b ? c:0))
#define saddr addr.sin_addr.s_addr
#define MAXPLAYERS 80
typedef struct wq_tag {
int fd;
struct wq_tag *next_tag;
} wq_tag;
int Numplayers;
int Numwaiting;
int Deadchildren;
static wq_tag *First_wait;
static int Waitsock;
static fd_set Sockets;
extern int Port;
/**********************************************************************/
/* sock_init */
/**********************************************************************/
/* This function initializes the socket that is used to accept new */
/* connections on. */
void sock_init(port, debug)
int port;
int debug;
{
struct sockaddr_in addr;
struct linger ling;
int n, i;
extern char report;
if(debug) {
FD_SET(0, &Sockets);
FD_SET(1, &Sockets);
FD_SET(2, &Sockets);
}
signal(SIGPIPE, SIG_IGN);
signal(SIGTERM, SIG_IGN);
signal(SIGCHLD, child_died);
Tablesize = getdtablesize();
if (Tablesize > PMAX){
Tablesize = PMAX;
logf("Tablesize greater than PMAX\n");
}
Waitsock = socket(AF_INET, SOCK_STREAM, 0);
if(Waitsock < 0)
exit(-1);
FD_SET(Waitsock, &Sockets);
addr.sin_addr.s_addr = INADDR_ANY;
addr.sin_port = htons(port);
if (report){
i = 1;
setsockopt(Waitsock, SOL_SOCKET, SO_REUSEADDR, &i, sizeof(int));
}
n = bind(Waitsock, (struct sockaddr *) &addr, sizeof(addr));
if(n < 0)
exit(-1);
ling.l_onoff = ling.l_linger = 0;
setsockopt(Waitsock, SOL_SOCKET, SO_LINGER, (char *)&ling,
sizeof(struct linger));
listen(Waitsock, 5);
i=1;
ioctl(Waitsock, FIONBIO, &i);
}
/**********************************************************************/
/* sock_loop */
/**********************************************************************/
/* This function is the main loop of the entire program. It constantly */
/* checks for new input, outputs players' output buffers, handles the */
/* players' commands and updates the game. */
void sock_loop()
{
while(1) {
if(Deadchildren) reap_children();
io_check();
output_buf();
handle_commands();
update_game();
}
}
/**********************************************************************/
/* io_check */
/**********************************************************************/
/* This function takes a look at all the sockets that are being used at */
/* the time, and determines which ones have input waiting on them. The */
/* ones that do call accept_input to have their input buffers updated. */
/* If the wait socket indicates input is ready to read, that means a */
/* new connection to the game must be accepted. */
int io_check()
{
fd_set sockcheck;
short rtn=0, i;
static struct timeval t = {0L, 75000L};
sockcheck = Sockets;
/* t.tv_usec = T_USEC; */
/* t.tv_sec = 0; */
t.tv_usec = 75000L;
if(select(Tablesize, &sockcheck, 0, 0, &t) > 0) {
for(i=0; i<Tablesize; i++) {
if(FD_ISSET(i, &sockcheck)) {
if(i != Waitsock)
rtn |= accept_input(i);
else
accept_connect();
}
}
}
return(rtn);
}
/**********************************************************************/
/* accept_connect */
/**********************************************************************/
/* This function accepts a new connection on the wait socket so that a */
/* new player can begin playing. The player's iobuf structure is init- */
/* ialized and a spot is marked in the player and socket arrays for the */
/* player. */
void accept_connect()
{
int len, fd, i=1, pid;
iobuf *io;
extra *extr;
struct linger ling;
struct sockaddr_in addr;
char *inetname(), path[127],
port1str[10], port2str[10];
addr.sin_family = AF_INET;
addr.sin_port = htons(Port);
addr.sin_addr.s_addr = INADDR_ANY;
len = sizeof(struct sockaddr_in);
fd = accept(Waitsock, (struct sockaddr *) &addr, &len);
if (fd < 0)
merror("accept_connect", FATAL);
ioctl(fd, FIONBIO, &i);
ling.l_onoff = ling.l_linger = 0;
setsockopt(fd, SOL_SOCKET, SO_LINGER, (char *)&ling,
sizeof(struct linger));
io = (iobuf *)malloc(sizeof(iobuf));
extr = (extra *)malloc(sizeof(extra));
if(!io || !extr)
merror("accept_connect", FATAL);
Ply[fd].io = io;
Ply[fd].ply = 0;
Ply[fd].extr = extr;
zero(extr, sizeof(extra));
zero(io, sizeof(iobuf));
io->ltime = time(0);
io->intrpt = 1;
strcpy(io->address, inetname(addr.sin_addr));
pid = vfork();
if(!pid) {
sprintf(path, "%s/auth", BINPATH);
sprintf(port1str, "%d", ntohs(addr.sin_port));
sprintf(port2str, "%d", Port);
execl(path, "auth", io->address, port1str, port2str, 0);
exit(0);
}
else {
strcpy(io->userid, "unknown");
io->lookup_pid = pid;
}
FD_SET(fd, &Sockets);
if(Numplayers > Tablesize-2) {
print(fd, "Game full. Try again later.\n");
disconnect(fd);
return;
}
else if(Numplayers >= MAXPLAYERS &&
((unsigned)(ntohl(saddr))>>24) != 127) {
if(Numwaiting > MAXPLAYERS) {
write(fd, "Queue full.\n\r", 13);
disconnect(fd);
return;
}
add_wait(fd);
RETURN(fd, waiting, 1);
}
init_connect(fd);
}
/************************************************************************/
/* init_connect */
/************************************************************************/
/* This function sets up the player using the fd'th input socket. */
void init_connect(fd)
int fd;
{
int i;
/*************************************************************/
/* The following lines must be left intact as part of the */
/* copyright agreement. */
/*************************************************************/
print(fd, "\nMordor v2.5 Beta (C) 1992, 1995");
print(fd, "\nProgrammed by Brett J. Vickers");
print(fd, "\nEnhancements by Steve Smith and Brooke Paul");
/*************************************************************/
/*************************************************************/
Ply[fd].io->intrpt |= 2;
Numplayers++;
if((i = locked_out(fd)) > 1) {
print(fd, "\nA password is required to play from that site.");
print(fd, "\nPlease enter site password: ");
output_buf();
RETURN(fd, login, 0);
}
else if(i) {
disconnect(fd);
return;
}
Ply[fd].io->ltime = time(0);
print(fd, "\n\nPlease enter name: ");
output_buf();
RETURN(fd, login, 1);
}
/************************************************************************/
/* locked_out */
/************************************************************************/
/* This function determines if the player on socket number, fd, is on */
/* a site that is being locked out. If the site is password locked, */
/* then 2 is returned. If it's completely locked, 1 is returned. If */
/* it's not locked out at all, 0 is returned. */
int locked_out(fd)
int fd;
{
int i;
for(i=0; i<Numlockedout; i++) {
if(!addr_equal(Lockout[i].address, Ply[fd].io->address))
continue;
if(Lockout[i].password[0]) {
strcpy(Ply[fd].extr->tempstr[0], Lockout[i].password);
return 2;
}
else {
write(fd, "\n\rYour site is locked out.\n\r", 28);
return 1;
}
}
return 0;
}
/************************************************************************/
/* addr_equal */
/************************************************************************/
/* This function determines if two internet addresses are equal and */
/* allows for wild-cards. */
int addr_equal(str1, str2)
char *str1;
char *str2;
{
while(*str1 && *str2) {
if(*str1 == '*') {
while(*str2 != '.' && *str2) str2++;
str1++;
continue;
}
else if(*str1 != *str2)
return(0);
str1++; str2++;
}
if(!*str1 && !*str2) return(1);
else return(0);
}
/**********************************************************************/
/* accept_input */
/**********************************************************************/
/* This function is called when a player's socket indicates that there */
/* is input waiting. The socket is read from, and the input is copied */
/* into that player's input buffer. If the last character entered is */
/* a carriage return, then the player's interrupt flag is set high. */
int accept_input(fd)
int fd;
{
char buf[128], lastchar;
int i, n, prev, itail, ihead;
n = read(fd, buf, 127);
if(n<=0)
Ply[fd].io->commands = -1; /* Connection dropped */
else {
ihead = Ply[fd].io->ihead;
lastchar = 0;
itail = Ply[fd].io->itail;
for(i=0; i<n; i++) {
if(buf[i] > 31 || (buf[i] == '\n' && lastchar != '\r')
|| buf[i] == '\r' || buf[i] == '\b') {
lastchar = buf[i];
if(buf[i] == '\r') buf[i] = '\n';
if(buf[i] == '\n') Ply[fd].io->commands++;
else if(buf[i] == '\b' && ihead != itail) {
prev = ihead-1 < 0 ? IBUFSIZE-1:ihead-1;
if(Ply[fd].io->input[prev] == '%')
ihead -= 2;
else
ihead--;
if(ihead < 0)
ihead = IBUFSIZE + ihead;
continue;
}
else if(buf[i] == '\b') continue;
Ply[fd].io->input[ihead] = buf[i];
ihead = (ihead + 1) % IBUFSIZE;
if(ihead == itail)
itail = (itail + 1) % IBUFSIZE;
if(buf[i] == '%') {
Ply[fd].io->input[ihead] = buf[i];
ihead = (ihead + 1) % IBUFSIZE;
if(ihead == itail)
itail = (itail + 1) % IBUFSIZE;
}
}
}
Ply[fd].io->ihead = ihead;
Ply[fd].io->itail = itail;
Ply[fd].io->ltime = time(0);
if(buf[n-1] == '\n' || buf[n-1] == '\r')
Ply[fd].io->intrpt |= 1;
else
Ply[fd].io->intrpt &= ~1;
}
return(0);
}
/**********************************************************************/
/* output_buf */
/**********************************************************************/
/* This function outputs the contents of all players' buffers when that */
/* player is able to be interrupted, or when that player's output buffer */
/* has reached a specific high-water mark (75% of buffer size). */
void output_buf()
{
char str[20], *pstr;
int i, n;
int otail, ohead;
for(i=0; i<Tablesize; i++) {
if(FD_ISSET(i, &Sockets) && Ply[i].io) {
otail = Ply[i].io->otail;
ohead = Ply[i].io->ohead;
if(ohead == otail)
continue;
if(Ply[i].io->commands == -1) {
disconnect(i);
continue;
}
if(Ply[i].io->intrpt & 1) {
if(Ply[i].ply)
if(Ply[i].ply->fd > -1 &&
F_ISSET(Ply[i].ply, PNOCMP)) {
n = write(i, "\n\r", 2);
if(Spy[i] > -1)
write(Spy[i], "\n\r", 2);
}
n = write(i, &Ply[i].io->output[otail],
ohead>otail ? ohead-otail:OBUFSIZE-otail);
if(Spy[i] > -1) write(Spy[i],
&Ply[i].io->output[otail],
ohead>otail ? ohead-otail:OBUFSIZE-otail);
if(otail > ohead) {
n+= write(i, Ply[i].io->output, ohead);
if(Spy[i] > -1)
write(Spy[i], Ply[i].io->output, ohead);
}
/*
if(n < buflen(ohead, otail, OBUFSIZE))
merror("output_buf", NONFATAL);
*/
otail = ohead;
Ply[i].io->otail = otail;
if(Ply[i].ply) {
pstr = ply_prompt(Ply[i].ply);
n = write(i, pstr, strlen(pstr));
if(Spy[i] > -1)
write(Spy[i],pstr,strlen(pstr));
}
}
if(buflen(ohead, otail, OBUFSIZE) > (OBUFSIZE*3)/4) {
n = write(i, &Ply[i].io->output[otail],
ohead>otail ? ohead-otail:OBUFSIZE-otail);
if(Spy[i] > -1) write(Spy[i],
&Ply[i].io->output[otail],
ohead>otail ? ohead-otail:OBUFSIZE-otail);
if(otail > ohead) {
n+= write(i, Ply[i].io->output, ohead);
if(Spy[i] > -1)
write(Spy[i], Ply[i].io->output, ohead);
}
/*
if(n < buflen(ohead, otail, OBUFSIZE))
merror("output_buf", NONFATAL);
*/
otail = ohead;
Ply[i].io->otail = otail;
}
}
}
}
/**********************************************************************/
/* print */
/**********************************************************************/
/* This function acts just like printf, except it outputs the */
/* formatted text string to a given socket's output buffer. The */
/* socket number is the first parameter. */
void print(fd, fmt, i1, i2, i3, i4, i5, i6)
int fd;
char *fmt;
int i1, i2, i3, i4, i5, i6;
{
char msg[2048];
char *fmt2;
int i = 0, j = 0, k, n, otail, ohead;
int num, loc, ind = -1, len, flags = 0;
int arg[6];
char type;
if(fd == -1 || fd > Tablesize)
return;
if(!Ply[fd].io)
return;
if(Ply[fd].ply) {
if(F_ISSET(Ply[fd].ply, PDINVI))
flags |= INV;
if(F_ISSET(Ply[fd].ply, PDMAGI))
flags |= MAG;
}
len = strlen(fmt);
fmt2 = (char *)malloc(len+1);
if(!fmt2)
merror("print", FATAL);
arg[0] = i1; arg[1] = i2; arg[2] = i3;
arg[3] = i4; arg[4] = i5; arg[5] = i6;
/* Check for %m, %M, %i and %I and modify arguments as necessary */
do {
if(fmt[i] == '%') {
fmt2[j++] = fmt[i];
num = 0; k = i;
do {
k++;
if((fmt[k] >= 'a' && fmt[k] <= 'z') ||
(fmt[k] >= 'A' && fmt[k] <= 'Z') ||
fmt[k] == '%') {
loc = k;
type = fmt[k];
break;
}
else if(fmt[k] >= '0' && fmt[k] <= '9')
num = num*10 + fmt[k]-'0';
} while(k < len);
if(type == '%') {
fmt2[j++] = '%';
i++; i++;
continue;
}
ind++;
if(type != 'm' && type != 'M' &&
type != 'i' && type != 'I') {
i++;
continue;
}
i = loc + 1;
fmt2[j++] = 's';
switch(type) {
case 'm':
arg[ind] = (int)crt_str(arg[ind], num, flags);
continue;
case 'M':
arg[ind] = (int)crt_str(arg[ind], num,
flags|CAP);
continue;
case 'i':
arg[ind] = (int)obj_str(arg[ind], num, flags);
continue;
case 'I':
arg[ind] = (int)obj_str(arg[ind], num,
flags|CAP);
continue;
}
}
fmt2[j++] = fmt[i++];
} while (i < len);
fmt2[j] = 0;
sprintf(msg, fmt2, arg[0], arg[1], arg[2], arg[3], arg[4], arg[5]);
free(fmt2);
n = strlen(msg);
if(n > 78) {
delimit(msg);
n = strlen(msg);
}
ohead = Ply[fd].io->ohead;
otail = Ply[fd].io->otail;
for(i=0; i<n; i++) {
Ply[fd].io->output[ohead] = msg[i];
ohead = (ohead + 1) % OBUFSIZE;
if(ohead == otail)
otail = (otail + 1) % OBUFSIZE;
if(msg[i] == '\n') {
Ply[fd].io->output[ohead] = '\r';
ohead = (ohead + 1) % OBUFSIZE;
if(ohead == otail)
otail = (otail + 1) % OBUFSIZE;
}
}
Ply[fd].io->ohead = ohead;
Ply[fd].io->otail = otail;
}
/**********************************************************************/
/* handle_commands */
/**********************************************************************/
/* This function strips out the first command in each player's input */
/* buffer, and then sends that command to the player's next function */
/* of input with the appropriate parameter. */
void handle_commands()
{
int i, j;
int itail, ihead;
char buf[IBUFSIZE+1];
for(i=0; i<Tablesize; i++) {
if(FD_ISSET(i, &Sockets) && Ply[i].io) {
if(Ply[i].io->commands == -1) {
disconnect(i);
continue;
}
if(!Ply[i].io->commands) continue;
itail = Ply[i].io->itail;
ihead = Ply[i].io->ihead;
if(itail == ihead) continue;
for(j=0; j<IBUFSIZE; j++) {
if(itail == ihead) {
buf[j] = 0;
break;
}
if(Ply[i].io->input[itail] == 13 ||
Ply[i].io->input[itail] == 10) {
itail = (itail + 1) % IBUFSIZE;
buf[j] = 0;
break;
}
buf[j] = Ply[i].io->input[itail];
itail = (itail + 1) % IBUFSIZE;
}
Ply[i].io->itail = itail;
Ply[i].io->commands--;
if(Spy[i] > -1) {
write(Spy[i], buf, strlen(buf));
write(Spy[i], "\n\r", 2);
}
(*Ply[i].io->fn) (i, Ply[i].io->fnparam, buf);
}
}
}
/**********************************************************************/
/* disconnect */
/**********************************************************************/
/* This function drops the connection to the player on the socket specified */
/* by the first parameter, clears his spot in the socket bit-array, and */
/* removes him from the player array by freeing all memory taken by him. */
void disconnect(fd)
int fd;
{
int i;
etag *ign, *temp;
wq_tag *wq;
close(fd);
FD_CLR(fd, &Sockets);
Spy[fd] = -1;
if(Ply[fd].io) {
if(Ply[fd].io->intrpt & 2)
Numplayers--;
free(Ply[fd].io);
Ply[fd].io = 0;
}
if(Ply[fd].extr) {
ign = Ply[fd].extr->first_ignore;
while(ign) {
temp = ign;
ign = ign->next_tag;
free(temp);
}
free(Ply[fd].extr);
Ply[fd].extr = 0;
}
if(Ply[fd].ply) {
if(F_ISSET(Ply[fd].ply, PSPYON)) {
for(i=0; i<Tablesize; i++)
if(Spy[i] == fd) Spy[i] = -1;
F_CLR(Ply[fd].ply, PSPYON);
}
if(Ply[fd].ply->fd > -1) {
uninit_ply(Ply[fd].ply);
save_ply(Ply[fd].ply->name, Ply[fd].ply);
}
free_crt(Ply[fd].ply);
Ply[fd].ply = 0;
}
else {
for(wq = First_wait, i=1; wq; wq = wq->next_tag, i++)
if(wq->fd == fd) {
remove_wait(i);
break;
}
}
if(Numwaiting && Numplayers < MAXPLAYERS) {
i = remove_wait(1);
if ( i != -1){
print(i, "%c", 7);
init_connect(i);
}
}
}
/**********************************************************************/
/* broadcast */
/**********************************************************************/
/* This function broadcasts a message to all the players that are in the */
/* game. If they have the NO-BROADCAST flag set, then they will not see */
/* it. */
void broadcast(fmt, i1, i2, i3, i4, i5, i6)
char *fmt;
int i1, i2, i3, i4, i5, i6;
{
char fmt2[1024];
int i;
strcpy(fmt2, fmt);
strcat(fmt2, "\n");
for(i=0; i<Tablesize; i++) {
if(FD_ISSET(i, &Sockets) && Ply[i].ply)
if(!F_ISSET(Ply[i].ply, PNOBRD) && Ply[i].ply->fd > -1)
print(i, fmt2, i1, i2, i3, i4, i5, i6);
}
}
/**********************************************************************/
/* broadcast_wiz */
/**********************************************************************/
/* This function broadcasts a message to all the DM's who are on at the */
/* time. */
void broadcast_wiz(fmt, i1, i2, i3, i4, i5, i6)
char *fmt;
int i1, i2, i3, i4, i5, i6;
{
char fmt2[1024];
int i;
strcpy(fmt2, fmt);
strcat(fmt2, "\n");
for(i=0; i<Tablesize; i++) {
if(FD_ISSET(i, &Sockets) && Ply[i].ply)
if(Ply[i].ply->fd > -1 && Ply[i].ply->class >= CARETAKER){
ANSI(i,YELLOW);
print(i, fmt2, i1, i2, i3, i4, i5, i6);
ANSI(i,WHITE);
}
}
}
/**********************************************************************/
/* broadcast_eaves */
/**********************************************************************/
/* This function broadcasts a message to all the DM's who are on at the */
/* time and have the eavesdropping flag set. */
void broadcast_eaves(fmt, i1, i2, i3, i4, i5, i6)
char *fmt;
int i1, i2, i3, i4, i5, i6;
{
char fmt2[1024];
int i;
strcpy(fmt2, fmt);
strcat(fmt2, "\n");
for(i=0; i<Tablesize; i++) {
if(FD_ISSET(i, &Sockets) && Ply[i].ply)
if(Ply[i].ply->fd > -1 &&
Ply[i].ply->class >= CARETAKER &&
F_ISSET(Ply[i].ply, PEAVES))
print(i, fmt2, i1, i2, i3, i4, i5, i6);
}
}
/**********************************************************************/
/* broadcast_rom */
/**********************************************************************/
/* This function outputs a message to everyone in the room specified */
/* by the integer in the second parameter. If the first parameter */
/* is greater than -1, then if the player specified by that file */
/* descriptor is present in the room, he is not given the message */
void broadcast_rom(ignore, rm, fmt, i1, i2, i3, i4, i5, i6)
int ignore, rm;
char *fmt;
int i1, i2, i3, i4, i5, i6;
{
char fmt2[1024];
int i;
strcpy(fmt2, fmt);
strcat(fmt2, "\n");
for(i=0; i<Tablesize; i++) {
if(FD_ISSET(i, &Sockets) && Ply[i].ply)
if(Ply[i].ply->rom_num == rm && Ply[i].ply->fd > -1
&& i != ignore )
print(i, fmt2, i1, i2, i3, i4, i5, i6);
}
}
/**********************************************************************/
/* broadcast_rom2 */
/**********************************************************************/
/* This function is the same as broadcast_rom except that it will ignore */
/* two people in a room. */
void broadcast_rom2(ignore1, ignore2, rm, fmt, i1, i2, i3, i4, i5, i6)
int ignore1, ignore2, rm;
char *fmt;
int i1, i2, i3, i4, i5, i6;
{
char fmt2[1024];
int i;
strcpy(fmt2, fmt);
strcat(fmt2, "\n");
for(i=0; i<Tablesize; i++) {
if(FD_ISSET(i, &Sockets) && Ply[i].ply)
if(Ply[i].ply->rom_num == rm && Ply[i].ply->fd > -1
&& i != ignore1 && i != ignore2)
print(i, fmt2, i1, i2, i3, i4, i5, i6);
}
}
/************************************************************************/
/* inetname */
/************************************************************************/
/* This function returns the internet address of the address structure */
/* passed in as the first parameter. */
char *inetname(in)
struct in_addr in;
{
register char *cp=0;
static char line[50];
struct hostent *hp;
struct netent *np;
static char domain[81];
static int first = 1;
int net, lna;
#ifdef GETHOSTBYNAME
if (first) {
first = 0;
if (gethostname(domain, 80) == 0 &&
(cp = index(domain, '.')))
(void) strcpy(domain, cp + 1);
else
domain[0] = 0;
}
cp = 0;
if (in.s_addr != INADDR_ANY) {
net = inet_netof(in);
lna = inet_lnaof(in);
if (lna == INADDR_ANY) {
np = getnetbyaddr(net, AF_INET);
if (np)
cp = np->n_name;
}
if (cp == 0) {
hp = gethostbyaddr((char *)&in, sizeof (in), AF_INET);
if (hp) {
if ((cp = index(hp->h_name, '.')) &&
!strcmp(cp + 1, domain))
*cp = 0;
cp = hp->h_name;
}
}
}
#endif
if (in.s_addr == INADDR_ANY)
strcpy(line, "*");
else if (cp)
strcpy(line, cp);
else {
in.s_addr = ntohl(in.s_addr);
#define C(x) ((x) & 0xff)
sprintf(line, "%u.%u.%u.%u", C(in.s_addr >> 24),
C(in.s_addr >> 16), C(in.s_addr >> 8), C(in.s_addr));
}
return (line);
}
/************************************************************************/
/* add_wait */
/************************************************************************/
/* This function adds the descriptor in the first parameter to the */
/* waiting queue. */
void add_wait(fd)
int fd;
{
wq_tag *new_wq, *wq;
new_wq = (wq_tag *)malloc(sizeof(wq_tag));
new_wq->next_tag = 0;
new_wq->fd = fd;
if(!First_wait) {
First_wait = new_wq;
Numwaiting = 1;
}
else {
wq = First_wait;
while(wq->next_tag)
wq = wq->next_tag;
wq->next_tag = new_wq;
Numwaiting++;
}
print(fd, "The game is full.\nYou are player #%d in the waiting queue.\n", Numwaiting);
}
/************************************************************************/
/* remove_wait */
/************************************************************************/
/* This function removes the i'th player from the waiting queue. */
int remove_wait(i)
int i;
{
int j, fd;
wq_tag *wq, *prev;
long t;
char str[50];
wq = First_wait;
/* write is being used here to check to see if the given
file desc. is still valid. Theorically, only one write is
needed, but for some reason 2 writes are needed */
write(wq->fd," ",1);
if(i == 1) {
if (write(wq->fd,"\n",1) == -1){
fd = -1;
}
else
fd = wq->fd;
First_wait = wq->next_tag;
}
else {
for(j=1; j<i; j++) {
prev = wq;
wq = wq->next_tag;
}
fd = wq->fd;
prev->next_tag = wq->next_tag;
}
free(wq);
Numwaiting--;
for(wq=First_wait, j=1; wq; wq=wq->next_tag, j++)
if(j >= i) print(wq->fd, "You are player #%d in the waiting queue.\n", j);
output_buf();
return(fd);
}
void waiting(fd, param, str)
int fd;
int param;
char *str;
{
RETURN(fd, waiting, 1);
}
/************************************************************************/
/* child_died */
/************************************************************************/
/* This function gets called when a SIGCHLD signal is sent to the */
/* program. */
void child_died()
{
Deadchildren++;
signal(SIGCHLD, child_died);
}
/************************************************************************/
/* reap_children */
/************************************************************************/
/* This program goes through and kills off (waits for) each child */
/* that has completed processing to avoid zombie processes. */
/* If the child was an authentication process, then the information */
/* it returned is looked up in the file it saved. */
void reap_children()
{
int pid, i, found, status;
char filename[127], userid[80], address[80], timestr[80];
FILE *fp;
long t;
t = time(0);
strcpy(timestr, (char *)ctime(&t));
timestr[strlen(timestr)-1] = 0;
while(Deadchildren > 0) {
Deadchildren--;
found = -1;
pid = wait(&status);
sprintf(filename, "%s/auth/lookup.%d", LOGPATH, pid);
for(i=0; i<Tablesize; i++) {
if(Ply[i].io && Ply[i].io->lookup_pid == pid) {
found = i;
break;
}
}
if(found < 0) {
if(file_exists(filename)) unlink(filename);
continue;
}
fp = fopen(filename, "r");
if(!fp) continue;
fscanf(fp, "%s %s", userid, address);
if(strlen(userid))
userid[8] = 0;
if(strlen(address))
address[39] = 0;
fclose(fp);
unlink(filename);
strcpy(Ply[found].io->userid, userid);
logf("%s: %s@%s (%s@%s) connected.\n", timestr,
userid, address, userid, Ply[found].io->address);
if(strcmp(address, "UNKNOWN"))
strcpy(Ply[found].io->address, address);
}
/* just in case, kill off any zombies */
wait4(-1, &status, WNOHANG, (struct rusage *)0);
}